using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Serialization;
using Awaiter;
using Nsb.Classes;
using Yoshi.Classes;
using YoshiBase.Classes;
using jQueryApi;

namespace YesPlayLove.Classes
{
    [IgnoreNamespace]
    public class EmailData : SavableData
    {
        public const string SentRx = "sent";
        public const string RcvdRx = "rcvd";

        private const string PartitionKeyLists = "db/email/lists";
        private const string PartitionKeyConvs = "db/email/convs";
        //private const string PartitionKeySent = "db/email/sent";
        //private const string PartitionKeyRcvd = "db/email/rcvd";
        private readonly string RowKeyRcvd;
        private readonly string RowKeySent;

        public EmailData()
        {
            RowKeySent = My.id;
            RowKeyRcvd = My.id;
        }

        public YoshiUser My
        {
            get { return Master.Profile.My; }
        }

        [AlternateSignature]
        public extern void GetMailListAw(Await awp);


        public void GetMailListAw(Await awp, string uid)
        {
            uid = Script.Value(uid, My.id);
            new Await()
                .AddAw(RetrieveBlobStringAw, PartitionKeyLists, uid)
                .HandleDl(Exceptions.BlobLoadError, Await.RethrowAw)
                .AddDx(delegate(Await aw) { awp[ResultRx] = aw[ResultRx] != null ? Json.Parse("[" + CleanListData((string)aw[ResultRx]) + "]") : null; })
                .Commit(awp);
        }

        public void SendMailAw(Await awp, string toId, string msg)
        {
            new Await()
                .AddAw(ProfileData.GetUserByIdAw, toId)
                .AddDx(
                    delegate
                    {
                        YoshiUser toUser = ProfileData.GetUserFromCacheById(toId);

                        //
                        // Store the email in key FROMeTO and key TOeFROM
                        //
                        Debug.Assert(toId != null, "toId != null");
                        EmailItem em = new EmailItem();
                        em.id = Formulas.NewId;
                        em.fromId = My.id;
                        em.toId = toId;
                        em.message = msg;
                        em.alias = My.alias;
                        em.unread = true;
                        em.createTime = (new Date()).GetTime();

                        string rowKey = My.id + "e" + toId;
                        AppendBlobStringAw(Await.AsyncAw, PartitionKeyConvs, rowKey, ResultRx, Json.Stringify(em));

                        rowKey = toId + "e" + My.id;
                        AppendBlobStringAw(Await.AsyncAw, PartitionKeyConvs, rowKey, ResultRx, Json.Stringify(em));

                        //
                        // Store the list items
                        //

                        //YoshiUser to = ProfileData.GetUserFromCacheById(toId);
                        EmailListItem el = new EmailListItem();
                        el.peek = msg.Substring(0, 60);

                        new Await()
                            .AddAw(UpdateStorageListsAw, My.id, toId, el)
                            .Commit(awp);

                        if (toUser.emmMessage)
                        {
                            Dictionary mail =
                                new Dictionary(
                                    "to", toUser.email,
                                    "from", My.email,
                                    "subject", String.Format(EmailTheme.MailSubject, toUser.alias),
                                    "content", msg
                                    );

                            new Await()
                                .AddAw(CloudMail.SendMailAw, mail)
                                .Commit();
                        }
                    })
                    .Commit()
                    ;
        }

        public void UpdateStorageListsAw(Await awp, string id1, string id2, object emListItem)
        {
            EmailListItem em1 = (EmailListItem)jQuery.ExtendObject((object)(new EmailListItem()), emListItem);
            EmailListItem em2 = (EmailListItem)jQuery.ExtendObject((object)(new EmailListItem()), emListItem);

            new Await()
                .AddAw(ProfileData.GetUserByIdAw, id2)
                .AddDx(
                    delegate
                    {
                        YoshiUser usr = ProfileData.GetUserFromCacheById(id2);

                        // My list as created
                        em1.fromId = usr.id;
                        em1.lastId = My.id;
                        em1.fAlias = usr.alias;
                        em1.lAlias = My.alias;

                        // Their list as created
                        em2.fromId = My.id;
                        em2.lastId = My.id;
                        em2.fAlias = My.alias;
                        em2.lAlias = My.alias;
                        
                    })
                .AddAw(UpdateListAw, id1, em1)
                .AddAw(UpdateListAw, id2, em2)
                .Commit(awp);
        }

        public void UpdateListAw(Await awp, string id1, object emListItem)
        {
            EmailListItem el = (EmailListItem) emListItem;
            new Await()
                .AddAw(GetMailListAw, id1)
                .HandleDl(Exceptions.BlobLoadError, Await.IgnoreAw)
                .AddDl(
                    delegate(Await aw)
                    {
                        List<EmailListItem> list;
                        if (Script.IsValue(aw[ResultRx]))
                            list = (List<EmailListItem>)aw[ResultRx];
                        else
                            list = new List<EmailListItem>();

                        bool found = false;

                        foreach (EmailListItem item in list)
                        {
                            if (item.fromId == el.fromId)
                            {
                                found = true;
                                if (el.unread)
                                {
                                    item.peek = el.peek;
                                    item.lastId = el.lastId;
                                    item.lAlias = el.lAlias;
                                }
                                item.unread = el.unread;
                                item.modifyTime = (new Date()).GetTime();
                                // TODO: Create a lock around this update - probably by doing update on server end instead of in client
                                ForceStoreBlob(PartitionKeyLists, id1);
                                StoreBlobStringAw(aw, new Dictionary("partitionKey", PartitionKeyLists, "rowKey", id1, "content", SimpleList(list)));
                                break;
                            }
                        }
                        if (!found)
                        {
                            AppendBlobStringAw(aw, PartitionKeyLists, id1, ResultRx, Json.Stringify(el));
                        }
                    }
                )
                .Commit(awp);
        }

        public void GetConvAw(Await awp, string fromId)
        {
            string rowKey = My.id + "e" + fromId;
            new Await()
                .AddAw(RetrieveBlobStringAw, PartitionKeyConvs, rowKey)
                .HandleDl(Exceptions.BlobLoadError, Await.AbortAw)
                .AddDx(delegate(Await aw) { awp[ResultRx] = aw[ResultRx] != null ? Json.Parse("[" + CleanListData((string)aw[ResultRx]) + "]") : null; })
                .Commit(awp);
        }

        //public void GetSentMailAw(Await awp, string rxKey)
        //{
        //    new Await()
        //        .AddAw(RetrieveBlobStringAw, PartitionKeySent, RowKeySent, rxKey)
        //        .HandleDl(Exceptions.BlobLoadError, Await.AbortAw)
        //        .AddDx(delegate(Await aw) { awp[rxKey] = aw[rxKey] != null ? Json.Parse("[" + CleanListData((string)aw[rxKey]) + "]") : null; })
        //        .Commit(awp);
        //}

        #region Test Data

        //private void LoadTestDataAw(Await awp, string rxKey)
        //{
        //    if (SiteTheme.Testing)
        //    {
        //        new Await()
        //            .AddDx(
        //                delegate(Await aw)
        //                {
        //                    foreach (EmailItem em in TestData.TestDataRcvdMail())
        //                    {
        //                        aw.InsertDl(aw.XCloserAw(new Action<Await, string, string, string, string>(AppendBlobStringAw), aw, PartitionKeyRcvd, RowKeyRcvd, RcvdRx, Json.Stringify(em)));
        //                    }
        //                }
        //            )
        //            .AddDx(
        //                delegate(Await aw)
        //                {
        //                    foreach (EmailItem em in TestData.TestDataSentMail())
        //                    {
        //                        aw.InsertDl(aw.XCloserAw(new Action<Await, string, string, string, string>(AppendBlobStringAw), aw, PartitionKeySent, RowKeySent, SentRx, Json.Stringify(em)));
        //                    }
        //                }
        //            )
        //            .AddDl(delegate(Await aw) { RetrieveBlobStringAw(aw, PartitionKeyRcvd, RowKeyRcvd, rxKey); })
        //            .HandleDl(Exceptions.BlobLoadError, Await.RethrowAw)
        //            .AddDx(delegate(Await aw) { awp[rxKey] = aw[rxKey]; })
        //            .Commit(awp);
        //    }
        //}

        #endregion Test Data
    }
}